﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Security.Cryptography.X509Certificates;

namespace Security.Encryption
{
   public class RSACertificateHandler
    {
       X509Certificate2 cert;
        private RSACryptoServiceProvider RSA;
        public RSACertificateHandler(string certificateSubjectName)
        {
            RSA = new RSACryptoServiceProvider();

             cert = new X509Certificate2();
            // The following code gets the cert from the keystore
            X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certCollection =
              store.Certificates.Find(X509FindType.FindBySubjectName,
                                      certificateSubjectName,
                                      false);
            X509Certificate2Enumerator enumerator = certCollection.GetEnumerator();
            cert = null;
            while (enumerator.MoveNext())
            {
                cert = enumerator.Current;
            }
             RSA = 
 (RSACryptoServiceProvider)cert.PrivateKey; 
                 //decBytes = rsa.Decrypt(ctext, false); 

           

        }
        public void CreateKeyPair()
        {
            RSA = new RSACryptoServiceProvider();
        }
        public string PublicKey
        {
            get { return cert.PublicKey.Key.ToXmlString(false);//.EncodedParameters.RawData;//.Export( X509ContentType.Cert);
            }
        }
        //public void LoadKeyPair(string pathToXMLFile)
        //{
        //    if (File.Exists(pathToXMLFile))
        //        RSA.FromXmlString(pathToXMLFile);
        //    else throw new FileNotFoundException(pathToXMLFile);
        //}
        //public void SaveKeyPairXML(bool savePrivateKey)
        //{
        //    using (TextWriter t = new StreamWriter("keys.xml"))
        //    {
        //        t.Write(RSA.ToXmlString(savePrivateKey));
        //        t.Close();
        //    }
        //}
        //public string GetPublicKeyXML()
        //{
        //    return RSA.ToXmlString(false);
        //}
        public string Encrypt(string data, string publicKey)
        {
            //X509Certificate2 recieverCert = new X509Certificate2();
            
            //recieverCert.PublicKey.Key.FromXmlString(publicKey);//.Import(publicKey);

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();// recieverCert.PublicKey.Key as RSACryptoServiceProvider;
            rsa.FromXmlString(publicKey);
            //Create a UnicodeEncoder to convert between byte array and string.
            UnicodeEncoding byteConverter = new UnicodeEncoding();

            //Create byte arrays to hold original, encrypted, and decrypted data.
            byte[] dataToEncrypt = byteConverter.GetBytes(data);
            byte[] encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false), false);
            
            //Display the decrypted plaintext to the console. 
            return byteConverter.GetString(encryptedData);

        }
        
        public string Decrypt(string data)
        {
            //Create a UnicodeEncoder to convert between byte array and string.
            UnicodeEncoding byteConverter = new UnicodeEncoding();
            byte[] encryptedData = byteConverter.GetBytes(data);
            byte[] decryptedData;
            //Pass the data to DECRYPT, the private key information 
            //(using RSACryptoServiceProvider.ExportParameters(true),
            RSACryptoServiceProvider rsa = 
 (RSACryptoServiceProvider)cert.PrivateKey;
            byte[] decBytes = rsa.Decrypt(encryptedData, false); 

            //and a boolean flag specifying no OAEP padding.
            decryptedData = RSADecrypt(encryptedData, RSA.ExportParameters(true), false);

            //Display the decrypted plaintext to the console. 
            return byteConverter.GetString(decryptedData);
        }
        //public string Decrypt(byte[] encryptedData)
        //{
        //    //Create a UnicodeEncoder to convert between byte array and string.
        //    UnicodeEncoding ByteConverter = new UnicodeEncoding();
        //    byte[] decryptedData;
        //    //Pass the data to DECRYPT, the private key information 
        //    //(using RSACryptoServiceProvider.ExportParameters(true),
        //    //and a boolean flag specifying no OAEP padding.
        //    decryptedData = RSADecrypt(encryptedData, RSA.ExportParameters(true), false);

        //    //Display the decrypted plaintext to the console. 
        //    return ByteConverter.GetString(decryptedData);
        //}
        static private byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
        {
            try
            {
                //Create a new instance of RSACryptoServiceProvider.
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();

                //Import the RSA Key information. This only needs
                //toinclude the public key information.
                RSA.ImportParameters(RSAKeyInfo);

                //Encrypt the passed byte array and specify OAEP padding.  
                //OAEP padding is only available on Microsoft Windows XP or
                //later.  
                return RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
            }
            //Catch and display a CryptographicException  
            //to the console.
            catch (CryptographicException e)
            {
                Console.WriteLine(e.Message);

                return null;
            }

        }

        static private byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
        {
            try
            {
                //Create a new instance of RSACryptoServiceProvider.
                RSACryptoServiceProvider tmp = new RSACryptoServiceProvider();

                //Import the RSA Key information. This needs
                //to include the private key information.
                tmp.ImportParameters(RSAKeyInfo);

                //Decrypt the passed byte array and specify OAEP padding.  
                //OAEP padding is only available on Microsoft Windows XP or
                //later.  
                return tmp.Decrypt(DataToDecrypt, DoOAEPPadding);
            }
            //Catch and display a CryptographicException  
            //to the console.
            catch (CryptographicException e)
            {
                Console.WriteLine(e.ToString());

                return null;
            }

        }
    }
}
